/*
 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2016年11月17日
 * <修改描述:>
 */
package com.tx.core.mybatis.assistant;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultFlag;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.BeanUtils;

import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.mybatis.sqlbuilder.SqlMapSQLBuilder;
import com.tx.core.util.TableInfoUtils;
import com.tx.core.util.TableInfoUtils.TableColumnInfo;

/**
 * Mapper构建助手扩展类<br/>
 * 该逻辑的调用，在设计上应该避免在修改statement期间出现业务调用的情况，不然可能出现不可预知的错误<br/>
 * <功能详细描述>
 *
 * @author Administrator
 * @version [版本号, 2016年11月17日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public abstract class AbstractSqlMapBuilderAssistant extends MapperBuilderAssistant {

	/** mybatis自动注册日志打印 */
	protected Logger logger = LoggerFactory.getLogger("mybatis.auto.sqlmap");

	// <if test=\"{} != null\">
	// <if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty({})\"><![CDATA[ AND {} {}
	// #{{}} ]]></if>
	// </if>
	protected static final String FORMATTER_OF_WHERE_ITEM = "" + "<if test=\"{} != null\">"
			+ "<if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty({})\">" + "<![CDATA[ {} {} {} #{{}} ]]>" + "</if>"
			+ "</if>";

	// <if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty({})\"><![CDATA[ AND {} {}
	// #{{}} ]]></if>
	protected static final String FORMATTER_OF_WHERE_ITEM_SIMPLE_TYPE = ""
			+ "<if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty({})\">" + "<![CDATA[ {} {} {} #{{}} ]]>" + "</if>";

	// <if test=\"ew.expression.normal != null and
	// !ew.expression.normal.isEmpty()\"><![CDATA[ AND
	// ${ew.expression.normal.sqlSegment} ]]>" + "</if>
	protected static final String FORMATTER_OF_WHERE_ITEM_WRAPPER = ""
			+ "<if test=\"ew.expression.normal != null and !ew.expression.normal.isEmpty()\">"
			+ "<![CDATA[ AND ${ew.expression.normal.sqlSegment} ]]>" + "</if>";

	// <if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty(parentIds)\">
	// AND parentId IN <foreach collection=\"parentIds\" open=\"(\" close=\")\"
	// separator=\",\" item=\"parentIdTemp\">#{parentIdTemp}</foreach>
	// </if>
	protected static final String FORMATTER_OF_PARENTID = ""
			+ "<if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty(parentIds)\">" + "AND parentId IN "
			+ "<foreach collection=\"parentIds\" open=\"(\" close=\")\" separator=\",\" item=\"parentIdTemp\">"
			+ "#{parentIdTemp}" + "</foreach>" + "</if>";

	// <if test="@com.tx.core.util.OgnlUtils@isNotEmpty(ew.sqlSet)"> ${ew.sqlSet},
	// </if>
	protected static final String FORMATTER_OF_SET_ITEM_4_WRAPPER = ""
			+ "<if test=\"@com.tx.core.util.OgnlUtils@isNotEmpty(ew.sqlSet)\">" + " ${ew.sqlSet}, " + "</if>";

	// <if test=\"_parameter.containsKey('{}')\"> {} = #{{},jdbcType={}}, </if> */
	protected static final String FORMATTER_OF_SET_ITEM = "<if "
			+ "test=\"_parameter.containsKey('{}')\"> {} = #{{},javaType={}}, </if>";

	// <if test=\"et != null\">{}</if>
	protected static final String FORMATTER_OF_SET_ITEM_4_ENTITY = "<if test=\"et != null\">{}</if>";

	// <if test="!_parameter.containsKey('description') and et.description != null">
	// description = #{et.description}, </if>
	protected static final String FORMATTER_OF_SET_ITEM_4_ENTITY_PROPERTY = ""
			+ "<if test=\"!_parameter.containsKey('{}') and et.{} != null\"> " + " {} = #{et.{}}, " + "</if>";

	// <choose>
	// <when test="ew.expression.orderBy != null and
	// !ew.expression.orderBy.isEmpty()">
	// ${ew.expression.orderBy.sqlSegment}
	// </when>
	// <otherwise>
	// ORDER BY createDate DESC
	// </otherwise>
	// </choose>
	protected static final String FORMATTER_OF_ORDERBY = "" + "<choose>"
			+ "<when test=\"ew.expression.orderBy != null and !ew.expression.orderBy.isEmpty()\"> ${ew.expression.orderBy.sqlSegment} </when>"
			+ "<otherwise>ORDER BY {} DESC</otherwise></choose>";

	/** <script>{}</script> 格式化器 */
	protected static final String FORMATTER_OF_SCRIPT = "<script>{}</script>";

	/** #{}属性格式化器 */
	protected static final String FORMATTER_OF_PROPERTY = "#{{}}";

	/** =條件 */
	protected static final String FORMATTER_OF_CONDITION_EQUAL = "=";

	/** 对应的类类型 */
	protected Class<?> entityType;

	/** 当前命名空间 */
	private String currentNamespace;

	/** <默认构造函数> */
	public AbstractSqlMapBuilderAssistant(Configuration configuration, Class<?> entityType) {
		super(configuration, entityType.getName());

		AssertUtils.notNull(configuration, "configuration is null.");
		AssertUtils.notNull(entityType, "type is null.");

		this.entityType = entityType;

		// 设置namespace
		this.currentNamespace = StringUtils.uncapitalize(entityType.getSimpleName());
		setCurrentNamespace(this.currentNamespace);
	}

	/**
	 * 是否是简单属性<br/>
	 * <功能详细描述>
	 *
	 * @param propertyDescriptor
	 * @return [参数说明]
	 * @return boolean [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected boolean hasTypeHandler(PropertyDescriptor propertyDescriptor) {
		AssertUtils.notNull(propertyDescriptor, "propertyDescriptor is null.");

		Class<?> type = propertyDescriptor.getPropertyType();
		if (BeanUtils.isSimpleValueType(type) || this.typeHandlerRegistry.getTypeHandler(type) != null) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 格式化脚本<br/>
	 * <功能详细描述>
	 *
	 * @param sql
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected String formatScript(String sql) {
		AssertUtils.notEmpty(sql, "sql is empty.");

		String script = MessageFormatter.arrayFormat(FORMATTER_OF_SCRIPT, new Object[] { sql }).getMessage();
		return script;
	}

	/**
	 * 格式化脚本<br/>
	 * <功能详细描述>
	 *
	 * @param columnPropertyName
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected String formatProperty(String columnPropertyName) {
		AssertUtils.notEmpty(columnPropertyName, "columnPropertyName is empty.");

		String formatProperty = MessageFormatter.arrayFormat(FORMATTER_OF_PROPERTY, new Object[] { columnPropertyName })
				.getMessage();
		return formatProperty;
	}

	/**
	 * 格式化WhereCondition条件<br/>
	 * <功能详细描述>
	 *
	 * @param columnName
	 * @param condition
	 * @param columnPropertyName
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected String formatAnd(String columnName, String condition, String columnPropertyName) {
		AssertUtils.notEmpty(columnName, "columnName is empty.");
		AssertUtils.notEmpty(condition, "condition is empty.");
		AssertUtils.notEmpty(columnPropertyName, "columnPropertyName is empty.");

		String sql = MessageFormatter
				.arrayFormat(FORMATTER_OF_WHERE_ITEM_SIMPLE_TYPE,
						new Object[] { columnPropertyName, "AND", columnName, condition, columnPropertyName })
				.getMessage();
		return sql;
	}

	/**
	 * 格式化WhereCondition条件<br/>
	 * <功能详细描述>
	 *
	 * @param column
	 * @param condition
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected String formatAnd(TableInfoUtils.TableColumnInfo column, String condition) {
		AssertUtils.notNull(column, "column is null.");
		AssertUtils.notEmpty(column.getColumnName(), "column.columnName is empty.");
		AssertUtils.notEmpty(column.getColumnPropertyName(), "column.columnPropertyName is empty.");
		AssertUtils.notEmpty(column.getPropertyName(), "column.propertyName is empty.");
		AssertUtils.notEmpty(condition, "condition is empty.");

		String sql = "";
		if (hasTypeHandler(column.getPropertyDescriptor())) {
			sql = MessageFormatter
					.arrayFormat(FORMATTER_OF_WHERE_ITEM_SIMPLE_TYPE, new Object[] { column.getColumnPropertyName(),
							"AND", column.getColumnName(), condition, column.getColumnPropertyName() })
					.getMessage();
		} else {
			sql = MessageFormatter.arrayFormat(FORMATTER_OF_WHERE_ITEM,
					new Object[] { column.getPropertyName(), column.getColumnPropertyName(), "AND",
							column.getColumnName(), condition, column.getColumnPropertyName() })
					.getMessage();
		}
		return sql;
	}

	/**
	 * 格式化WhereCondition条件<br/>
	 * <功能详细描述>
	 *
	 * @param column
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected String formatAndEqual(TableColumnInfo column) {
		AssertUtils.notNull(column, "column is null.");
		AssertUtils.notEmpty(column.getColumnName(), "column.columnName is empty.");
		AssertUtils.notEmpty(column.getColumnPropertyName(), "column.columnPropertyName is empty.");
		AssertUtils.notEmpty(column.getPropertyName(), "column.propertyName is empty.");

		String eqSQL = "";
		if (hasTypeHandler(column.getPropertyDescriptor())) {
			eqSQL = MessageFormatter
					.arrayFormat(FORMATTER_OF_WHERE_ITEM_SIMPLE_TYPE, new Object[] { column.getColumnPropertyName(),
							"AND", column.getColumnName(), "=", column.getColumnPropertyName() })
					.getMessage();
		} else {
			eqSQL = MessageFormatter.arrayFormat(FORMATTER_OF_WHERE_ITEM,
					new Object[] { column.getPropertyName(), column.getColumnPropertyName(), "AND",
							column.getColumnName(), "=", column.getColumnPropertyName() })
					.getMessage();
		}
		return eqSQL;
	}

	/**
	 * 输出格式化 = 的结构
	 * 
	 * @param propertyName
	 * @param columnName
	 * @return
	 */
	protected String formatAndEqual(String propertyName, String columnName) {
		AssertUtils.notEmpty(columnName, "columnName is empty.");

		String eqSQL = MessageFormatter.arrayFormat(FORMATTER_OF_WHERE_ITEM_SIMPLE_TYPE,
				new Object[] { propertyName, "AND", columnName, "=", columnName }).getMessage();
		return eqSQL;
	}

	/**
	 * 输出格式化 = 的结构
	 * 
	 * @param propertyName
	 * @param columnName
	 * @return
	 */
	protected String formatOrderBy(String defaultOrderColumnNames) {
		AssertUtils.notEmpty(defaultOrderColumnNames, "defaultOrderColumnNames is empty.");

		String orderSQL = MessageFormatter.arrayFormat(FORMATTER_OF_ORDERBY, new Object[] { defaultOrderColumnNames })
				.getMessage();
		return orderSQL;
	}

	/**
	 * 格式化Set项<br/>
	 * <功能详细描述>
	 *
	 * @param columnName
	 * @param propertyName
	 * @param javaType
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected String formatSetItem(String columnName, String propertyName, String nestedPropertyName,
			Class<?> javaType) {
		AssertUtils.notEmpty(columnName, "columnName is empty.");
		AssertUtils.notEmpty(propertyName, "propertyName is empty.");
		AssertUtils.notEmpty(nestedPropertyName, "nestedPropertyName is empty.");
		AssertUtils.notNull(javaType, "javaType is null.");

		return MessageFormatter.arrayFormat(FORMATTER_OF_SET_ITEM,
				new Object[] { propertyName, columnName, nestedPropertyName, javaType.getName() }).getMessage();
	}

	/**
	 * 实体Item
	 * 
	 * @param columnName
	 * @param propertyName
	 * @param nestedPropertyName
	 * @param javaType
	 * @return
	 */
	protected String formatSetEntityItem(String columnName, String propertyName, String nestedPropertyName) {
		AssertUtils.notEmpty(columnName, "columnName is empty.");
		AssertUtils.notEmpty(propertyName, "propertyName is empty.");
		AssertUtils.notEmpty(nestedPropertyName, "nestedPropertyName is empty.");

		return MessageFormatter.arrayFormat(FORMATTER_OF_SET_ITEM_4_ENTITY_PROPERTY,
				new Object[] { propertyName, propertyName, columnName, nestedPropertyName }).getMessage();
	}

	/**
	 * 实体Item
	 * 
	 * @param columnName
	 * @param propertyName
	 * @param nestedPropertyName
	 * @param javaType
	 * @return
	 */
	protected String formatSetEntity(String sets) {
		if (StringUtils.isBlank(sets)) {
			return "";
		}
		return MessageFormatter.arrayFormat(FORMATTER_OF_SET_ITEM_4_ENTITY, new Object[] { sets }).getMessage();
	}

	/**
	 * 调用该方法向Configuration中注册对应的SqlMap<br/>
	 * <功能详细描述> [参数说明]
	 *
	 * @return void [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public void registe() {
		// 添加resultMap
		Map<String, String> customizeColumn2PropertyMap = getColumn2PropertyMap();
		List<ResultMapping> resultMappings = new ArrayList<>();
		if (!MapUtils.isEmpty(customizeColumn2PropertyMap)) {
			for (Entry<String, String> entryTemp : customizeColumn2PropertyMap.entrySet()) {
				ResultMapping resultMapping = buildResultMapping(entryTemp.getKey(), entryTemp.getValue());
				resultMappings.add(resultMapping);
			}
		}
		String resultMapId = StringUtils.uncapitalize(this.entityType.getSimpleName()) + "Map";
		if (!this.configuration.hasResultMap(resultMapId)) {
			addResultMap(resultMapId, this.entityType, resultMappings);
		}

		String insertSQL = getInsertSQL();
		if (!StringUtils.isBlank(insertSQL)) {
			insertSQL = formatScript(insertSQL);

			if (!this.configuration.hasStatement(getInsertStatementName(), false)) {
				logger.info("<!-- --- 自动注入: insertSQL:--- -->");
				logger.info(insertSQL);
				addInsertMappedStatement(getInsertStatementName(), insertSQL, this.entityType);
			}
		}

		String deleteSQL = getDeleteSQL();
		if (!StringUtils.isBlank(deleteSQL)) {
			deleteSQL = formatScript(deleteSQL);

			if (!this.configuration.hasStatement(getDeleteStatementName(), false)) {
				logger.info("<!-- --- 自动注入: deleteSQL:--- -->");
				logger.info(deleteSQL);
				addDeleteMappedStatement(getDeleteStatementName(), deleteSQL, this.entityType);
			}
		}

		String updateSQL = getUpdateSQL();
		if (!StringUtils.isBlank(updateSQL)) {
			updateSQL = formatScript(updateSQL);

			if (!this.configuration.hasStatement(getUpdateStatementName(), false)) {
				logger.info("<!-- --- 自动注入: updateSQL:--- -->");
				logger.info(updateSQL);
				addUpdateMappedStatement(getUpdateStatementName(), updateSQL, Map.class);
			}
		}

		String findSQL = getFindSQL();
		if (!StringUtils.isBlank(findSQL)) {
			findSQL = formatScript(findSQL);

			if (!this.configuration.hasStatement(getFindStatementName(), false)) {
				logger.info("<!-- --- 自动注入: findSQL:--- -->");
				logger.info(findSQL);
				addFindMappedStatement(getFindStatementName(), findSQL, this.entityType, resultMapId);
			}
		}

		String querySQL = getQuerySQL();
		if (!StringUtils.isBlank(querySQL)) {
			querySQL = formatScript(querySQL);

			if (!this.configuration.hasStatement(getQueryStatementName(), false)) {
				logger.info("<!-- --- 自动注入: querySQL:--- -->");
				logger.info(querySQL);
				addFindMappedStatement(getQueryStatementName(), querySQL, Map.class, resultMapId);
			}
		}

		String countSQL = getCountSQL();
		if (!StringUtils.isBlank(countSQL)) {
			countSQL = formatScript(countSQL);

			if (!this.configuration.hasStatement(getCountStatmentName(), false)) {
				logger.info("<!-- --- 自动注入: queryCountSQL:--- -->");
				logger.info(countSQL);
				addCountMappedStatement(getCountStatmentName(), countSQL, Map.class, Integer.class);
			}
		}
	}

	/**
	 * 当前命名空间<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getNamespace() {
		return this.currentNamespace;
	}

	/**
	 * 获取insertSatement的name <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getInsertStatementName() {
		return this.currentNamespace + ".insert";
	}

	/**
	 * 获取deleteStatement的name <功能简述> <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getDeleteStatementName() {
		return this.currentNamespace + ".delete";
	}

	/**
	 * 获取updateStatement的name <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getUpdateStatementName() {
		return this.currentNamespace + ".update";
	}

	/**
	 * 获取findStatment的name <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getFindStatementName() {
		return this.currentNamespace + ".find";
	}

	/**
	 * 获取queryStatment的name <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getQueryStatementName() {
		return this.currentNamespace + ".query";
	}

	/**
	 * 获取countStatment的name <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public String getCountStatmentName() {
		return getQueryStatementName() + "Count";
	}

	/**
	 * 获取插入语句<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected abstract String getInsertSQL();

	/**
	 * 
	 * @param tableName
	 * @param column2propertyMap
	 * @param column2typeMap
	 * @return
	 */
	protected final String doBuildInsertSQL(String tableName, Map<String, String> column2propertyMap,
			Map<String, Class<?>> column2typeMap, boolean javaTypeNotNull) {
		AssertUtils.notEmpty(tableName, "tableName is empty.");
		AssertUtils.notEmpty(column2propertyMap, "column2propertyMap is empty.");
		if (column2typeMap == null) {
			column2typeMap = new HashMap<>();
		}

		SqlMapSQLBuilder sql = new SqlMapSQLBuilder();
		sql.INSERT_INTO(tableName);

		for (Entry<String, String> entryTemp : column2propertyMap.entrySet()) {
			if (column2typeMap.containsKey(entryTemp.getKey())) {
				if (javaTypeNotNull) {
					sql.VALUES(entryTemp.getKey(),
							formatProperty(entryTemp.getValue() + ",javaType=" + String.class.getName()));
				} else {
					sql.VALUES(entryTemp.getKey(), formatProperty(entryTemp.getValue()));
				}
			} else {
				sql.VALUES(entryTemp.getKey(), formatProperty(
						entryTemp.getValue() + ",javaType=" + column2typeMap.get(entryTemp.getKey()).getName()));
			}
		}

		String insertSQL = sql.toString();
		return insertSQL;
	}

	/**
	 * 获取插入语句<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected abstract String getDeleteSQL();

	/**
	 * 构建删除SQL
	 * 
	 * @param tableName
	 * @param deleteMap
	 * @return
	 */
	protected final String doBuildDeleteSQL(String tableName, Map<String, String> deleteMap) {
		AssertUtils.notEmpty(tableName, "tableName is empty.");
		AssertUtils.notEmpty(deleteMap, "deleteMap is empty.");

		SqlMapSQLBuilder sql = new SqlMapSQLBuilder();
		sql.DELETE_FROM(tableName);

		for (Entry<String, String> entryTemp : deleteMap.entrySet()) {
			sql.WHERE(formatAndEqual(entryTemp.getKey(), entryTemp.getValue()));
		}

		String deleteSQL = sql.toString();
		return deleteSQL;
	}

	/**
	 * 获取插入语句<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected abstract String getUpdateSQL();

	/**
	 * 构建更新的SQL
	 * 
	 * @param tableName
	 * @param column2propertyMap
	 * @param column2typeMap
	 * @param javaTypeNotNull
	 * @return
	 */
	protected final String doBuildUpdateSQL(String tableName, Map<String, String> column2propertyMap,
			Map<String, Class<?>> column2typeMap, boolean javaTypeNotNull, Map<String, String> updateMap) {
		AssertUtils.notEmpty(tableName, "tableName is empty.");
		AssertUtils.notEmpty(updateMap, "updateMap is empty.");

		SqlMapSQLBuilder sql = new SqlMapSQLBuilder();
		sql.UPDATE(tableName);

		for (Entry<String, String> entryTemp : column2propertyMap.entrySet()) {
			if (column2typeMap.containsKey(entryTemp.getKey())) {
				String setItem = formatSetItem(entryTemp.getKey(), entryTemp.getValue(), entryTemp.getValue(),
						String.class);
				sql.SET(setItem);
			} else {
				String setItem = formatSetItem(entryTemp.getKey(), entryTemp.getValue(), entryTemp.getValue(),
						column2typeMap.get(entryTemp.getKey()));
				sql.SET(setItem);
			}
		}
		sql.SET(FORMATTER_OF_SET_ITEM_4_WRAPPER);

		for (Entry<String, String> entryTemp : updateMap.entrySet()) {
			sql.WHERE(formatAndEqual(entryTemp.getKey(), entryTemp.getValue()));
		}
		sql.WHERE(FORMATTER_OF_WHERE_ITEM_WRAPPER);

		String updateSQL = sql.toString();
		return updateSQL;
	}

	/**
	 * 获取特殊的字段到属性的映射<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return Map<String, String> [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected Map<String, String> getColumn2PropertyMap() {
		return new HashMap<>();
	}

	/**
	 * 获取插入语句<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected abstract String getFindSQL();

	/**
	 * 构建findSql
	 * 
	 * @param tableName
	 * @param columnNames
	 * @param pkPropertyName
	 * @param pkColumnName
	 * @return
	 */
	protected final String doBuildFindSQL(String tableName, Set<String> columnNames, Map<String, String> findMap) {
		AssertUtils.notEmpty(tableName, "tableName is empty.");
		AssertUtils.notEmpty(columnNames, "columnNames is empty.");
		AssertUtils.notEmpty(findMap, "findMap is empty.");

		SqlMapSQLBuilder sql = new SqlMapSQLBuilder();
		for (String columnNameTemp : columnNames) {
			// 查询字段
			sql.FIND(columnNameTemp);
		}
		sql.FROM(tableName);

		for (Entry<String, String> entryTemp : findMap.entrySet()) {
			sql.WHERE(formatAndEqual(entryTemp.getKey(), entryTemp.getValue()));
		}
		String findSQL = sql.toString();
		return findSQL;
	}

	/**
	 * 获取插入语句<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected abstract String getQuerySQL();

	/**
	 * 构建querySql
	 * 
	 * @param tableName
	 * @param columnNames
	 * @param pkPropertyName
	 * @param pkColumnName
	 * @return
	 */
	protected final String doBuildQuerySQL(String tableName, Set<String> columnNames, Map<String, String> queryEqualMap,
			boolean hasParentIdProperty, String pkPropertyName, String pkColumnName, String defaultOrderColumnNames) {
		AssertUtils.notEmpty(tableName, "tableName is empty.");
		AssertUtils.notEmpty(columnNames, "columnNames is empty.");
		AssertUtils.notEmpty(queryEqualMap, "queryEqualMap is empty.");

		SqlMapSQLBuilder sql = new SqlMapSQLBuilder();
		for (String columnNameTemp : columnNames) {
			// 查询字段
			sql.QUERY(columnNameTemp);
		}
		sql.FROM(tableName);

		doBuildQueryCondition(queryEqualMap, hasParentIdProperty, pkPropertyName, pkColumnName, sql);
		sql.ORDER_BY(formatOrderBy(defaultOrderColumnNames));
		String querySQL = sql.toString();
		return querySQL;
	}

	/**
	 * 构建
	 * 
	 * @param queryEqualMap
	 * @param hasParentIdProperty
	 * @param pkPropertyName
	 * @param pkColumnName
	 * @param sql
	 */
	private final void doBuildQueryCondition(Map<String, String> queryEqualMap, boolean hasParentIdProperty,
			String pkPropertyName, String pkColumnName, SqlMapSQLBuilder sql) {
		sql.WHERE(FORMATTER_OF_WHERE_ITEM_WRAPPER);// 查询的其他条件
		if (hasParentIdProperty) {
			sql.WHERE(FORMATTER_OF_PARENTID);
		}
		for (Entry<String, String> entryTemp : queryEqualMap.entrySet()) {
			sql.WHERE(formatAndEqual(entryTemp.getKey(), entryTemp.getValue()));
		}
		sql.WHERE(formatAnd(pkColumnName, "<>", "exclude" + StringUtils.capitalize(pkPropertyName)));
	}

	/**
	 * 获取插入语句<br/>
	 * <功能详细描述>
	 *
	 * @return [参数说明]
	 * @return String [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected abstract String getCountSQL();

	/**
	 * 
	 * @param tableName
	 * @param queryEqualMap
	 * @param hasParentIdProperty
	 * @param pkPropertyName
	 * @param pkColumnName
	 * @return
	 */
	protected final String doBuildCountSQL(String tableName, Map<String, String> queryEqualMap,
			boolean hasParentIdProperty, String pkPropertyName, String pkColumnName) {
		AssertUtils.notEmpty(tableName, "tableName is empty.");
		AssertUtils.notEmpty(queryEqualMap, "queryEqualMap is empty.");

		SqlMapSQLBuilder sql = new SqlMapSQLBuilder();
		sql.COUNT();
		sql.FROM(tableName);
		doBuildQueryCondition(queryEqualMap, hasParentIdProperty, pkPropertyName, pkColumnName, sql);
		String querySQL = sql.toString();
		return querySQL;
	}

	/**
	 * 构建ResultMapping
	 * 
	 * @param propertyName
	 * @param columnName
	 * @return
	 */
	protected ResultMapping buildResultMapping(String propertyName, String columnName) {
		Class<?> javaType = null;
		return buildResultMapping(propertyName, columnName, javaType);
	}

	/**
	 * 构建ResultMapping
	 * 
	 * @param propertyName
	 * @param columnName
	 * @param javaType
	 * @return
	 */
	protected ResultMapping buildResultMapping(String propertyName, String columnName, Class<?> javaType) {
		Class<?> resultType = null;
		JdbcType jdbcType = null;

		String nestedSelect = null;// 是否存在nestedSelect
		String nestedResultMap = null;//
		String notNullColumn = null;
		String columnPrefix = null;
		Class<? extends TypeHandler<?>> typeHandler = null;
		List<ResultFlag> flags = null; // ??
		String resultSet = null;
		String foreignColumn = null;
		boolean lazy = true;
		ResultMapping rm = super.buildResultMapping(resultType, propertyName, columnName, javaType, jdbcType,
				nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandler, flags, resultSet,
				foreignColumn, lazy);
		return rm;
	}

	/**
	 * 保存MappedStatement <功能详细描述>
	 *
	 * @param resultMapId
	 * @param resultType
	 * @param resultMappings
	 * @return [参数说明]
	 * @return MappedStatement [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected ResultMap addResultMap(String resultMapId, Class<?> resultType, List<ResultMapping> resultMappings) {
		AssertUtils.notEmpty(resultMapId, "resultMapId is empty.");
		AssertUtils.notNull(resultType, "resultType is null.");
		AssertUtils.notNull(resultMappings, "resultMappings is null.");

		resultMapId = applyCurrentNamespace(resultMapId, false);// 获取对应的statement的id
		ResultMap resultMap = addResultMap(resultMapId, resultType, null, null, resultMappings, true);

		return resultMap;
	}

	/**
	 * 保存MappedStatement 该方法用于创建并保存一个用于插入操作的MappedStatement。
	 *
	 * @param id            MappedStatement的唯一标识符
	 * @param sql           执行插入操作的SQL语句
	 * @param parameterType 插入操作参数的类型
	 * @return 返回创建的MappedStatement对象
	 * @throws 无特定异常抛出，但可能会抛出由调用的方法或构造器引发的异常
	 * @see 无特定引用
	 */
	protected MappedStatement addInsertMappedStatement(String id, String sql, Class<?> parameterType) {
		// 确保id、sql和parameterType不为空
		AssertUtils.notEmpty(id, "id is empty.");
		AssertUtils.notEmpty(sql, "sql is empty.");
		AssertUtils.notNull(parameterType, "parameterType is null.");

		// 初始化Statement的配置参数
		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		Integer fetchSize = null;
		Integer timeout = null;

		// 配置缓存和刷新选项
		boolean flushCache = true;
		boolean useCache = false;
		boolean resultOrdered = false;

		// 初始化键相关属性
		String keyProperty = null;
		String keyColumn = null;
		// 配置数据库ID和结果集
		String databaseId = null;
		String resultSets = null;
		// 结果映射相关配置
		String resultMap = null;
		Class<?> resultType = null;

		// 参数映射配置
		String parameterMap = null;

		// 根据配置选择合适的KeyGenerator
		KeyGenerator keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
		// 获取语言驱动
		LanguageDriver lang = configuration.getLanguageDriver(null);

		// 创建SqlSource
		SqlSource sqlSource = lang.createSqlSource(configuration, sql, parameterType);

		// 应用当前命名空间到id
		id = applyCurrentNamespace(id, false);// 获取对应的statement的id
		// 创建并添加MappedStatement
		MappedStatement statement = addMappedStatement(id, sqlSource, statementType, SqlCommandType.INSERT, fetchSize,
				timeout, parameterMap, parameterType, resultMap, resultType, resultSetType, flushCache, useCache,
				resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, lang, resultSets);
		return statement;
	}

	/**
	 * 保存MappedStatement<br/>
	 * <功能详细描述>
	 *
	 * @param id
	 * @param sql
	 * @param parameterType
	 * @return [参数说明]
	 * @return MappedStatement [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected MappedStatement addDeleteMappedStatement(String id, String sql, Class<?> parameterType) {
		AssertUtils.notEmpty(id, "id is empty.");
		AssertUtils.notEmpty(sql, "sql is empty.");
		AssertUtils.notNull(parameterType, "parameterType is null.");

		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		Integer fetchSize = null;
		Integer timeout = null;

		boolean flushCache = true;
		boolean useCache = false;
		boolean resultOrdered = false;

		String keyProperty = null;
		String keyColumn = null;
		String databaseId = null;
		String resultSets = null;
		String resultMap = null;
		Class<?> resultType = null;

		String parameterMap = null;

		KeyGenerator keyGenerator = new NoKeyGenerator();
		LanguageDriver lang = configuration.getLanguageDriver(null);

		SqlSource sqlSource = lang.createSqlSource(configuration, sql, parameterType);

		id = applyCurrentNamespace(id, false);// 获取对应的statement的id
		MappedStatement statement = addMappedStatement(id, sqlSource, statementType, SqlCommandType.DELETE, fetchSize,
				timeout, parameterMap, parameterType, resultMap, resultType, resultSetType, flushCache, useCache,
				resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, lang, resultSets);
		return statement;
	}

	/**
	 * 保存MappedStatement<br/>
	 * <功能详细描述>
	 *
	 * @param id
	 * @param sql
	 * @param parameterType
	 * @return [参数说明]
	 * @return MappedStatement [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	protected MappedStatement addUpdateMappedStatement(String id, String sql, Class<?> parameterType) {
		AssertUtils.notEmpty(id, "id is empty.");
		AssertUtils.notEmpty(sql, "sql is empty.");

		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		Integer fetchSize = null;
		Integer timeout = null;

		boolean flushCache = true;
		boolean useCache = false;
		boolean resultOrdered = false;

		String keyProperty = null;
		String keyColumn = null;
		String databaseId = null;
		String resultSets = null;
		String resultMap = null;
		Class<?> resultType = null;

		String parameterMap = null;

		KeyGenerator keyGenerator = new NoKeyGenerator();
		LanguageDriver lang = configuration.getLanguageDriver(null);

		SqlSource sqlSource = lang.createSqlSource(configuration, sql, parameterType);

		id = applyCurrentNamespace(id, false);// 获取对应的statement的id
		MappedStatement statement = addMappedStatement(id, sqlSource, statementType, SqlCommandType.UPDATE, fetchSize,
				timeout, parameterMap, parameterType, resultMap, resultType, resultSetType, flushCache, useCache,
				resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, lang, resultSets);
		return statement;
	}

	/**
	 * 保存MappedStatement<br/>
	 * <功能详细描述>
	 *
	 * @param id
	 * @param sql
	 * @param parameterType
	 * @param resultMapId
	 * @return [参数说明]
	 * @return MappedStatement [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public MappedStatement addFindMappedStatement(String id, String sql, Class<?> parameterType, String resultMapId) {
		AssertUtils.notEmpty(id, "id is empty.");
		AssertUtils.notEmpty(sql, "sql is empty.");
		AssertUtils.notNull(parameterType, "parameterType is null.");
		AssertUtils.notEmpty(resultMapId, "resultMapId is empty.");

		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		Integer fetchSize = null;
		Integer timeout = null;

		boolean flushCache = false;
		boolean useCache = true;
		boolean resultOrdered = false;

		String keyProperty = null;
		String keyColumn = null;
		String databaseId = null;
		String resultSets = null;
		Class<?> resultType = null;

		String parameterMap = null;

		KeyGenerator keyGenerator = new NoKeyGenerator();
		LanguageDriver lang = configuration.getLanguageDriver(null);

		SqlSource sqlSource = lang.createSqlSource(configuration, sql, parameterType);

		id = applyCurrentNamespace(id, false);// 获取对应的statement的id
		MappedStatement statement = addMappedStatement(id, sqlSource, statementType, SqlCommandType.SELECT, fetchSize,
				timeout, parameterMap, parameterType, resultMapId, resultType, resultSetType, flushCache, useCache,
				resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, lang, resultSets);
		return statement;
	}

	/**
	 * 保存MappedStatement<br/>
	 * <功能详细描述>
	 *
	 * @param id
	 * @param sql
	 * @param parameterType
	 * @param resultMapId
	 * @return [参数说明]
	 * @return MappedStatement [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public MappedStatement addQueryMappedStatement(String id, String sql, Class<?> parameterType, String resultMapId) {
		AssertUtils.notEmpty(id, "id is empty.");
		AssertUtils.notEmpty(sql, "sql is empty.");
		AssertUtils.notNull(parameterType, "parameterType is null.");
		AssertUtils.notEmpty(resultMapId, "resultMapId is empty.");

		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		Integer fetchSize = null;
		Integer timeout = null;

		boolean flushCache = false;
		boolean useCache = true;
		boolean resultOrdered = false;

		String keyProperty = null;
		String keyColumn = null;
		String databaseId = null;
		String resultSets = null;
		Class<?> resultType = null;

		String parameterMap = null;

		KeyGenerator keyGenerator = new NoKeyGenerator();
		LanguageDriver lang = configuration.getLanguageDriver(null);

		SqlSource sqlSource = lang.createSqlSource(configuration, sql, parameterType);

		id = applyCurrentNamespace(id, false);// 获取对应的statement的id
		MappedStatement statement = addMappedStatement(id, sqlSource, statementType, SqlCommandType.SELECT, fetchSize,
				timeout, parameterMap, parameterType, resultMapId, resultType, resultSetType, flushCache, useCache,
				resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, lang, resultSets);
		return statement;
	}

	/**
	 * 保存MappedStatement<br/>
	 * <功能详细描述>
	 *
	 * @param id
	 * @param sql
	 * @param parameterType
	 * @param resultType
	 * @return [参数说明]
	 * @return MappedStatement [返回类型说明]
	 * @throws throws [异常类型] [异常说明]
	 * @see [类、类#方法、类#成员]
	 */
	public MappedStatement addCountMappedStatement(String id, String sql, Class<?> parameterType, Class<?> resultType) {
		AssertUtils.notEmpty(id, "id is empty.");
		AssertUtils.notEmpty(sql, "sql is empty.");
		AssertUtils.notNull(parameterType, "parameterType is null.");
		AssertUtils.notEmpty(resultType, "resultType is empty.");

		StatementType statementType = StatementType.PREPARED;
		ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
		Integer fetchSize = null;
		Integer timeout = null;

		boolean flushCache = false;
		boolean useCache = true;
		boolean resultOrdered = false;

		String keyProperty = null;
		String keyColumn = null;
		String databaseId = null;
		String resultSets = null;
		String resultMapId = null;

		String parameterMap = null;

		KeyGenerator keyGenerator = new NoKeyGenerator();
		LanguageDriver lang = configuration.getLanguageDriver(null);

		SqlSource sqlSource = lang.createSqlSource(configuration, sql, parameterType);

		id = applyCurrentNamespace(id, false);// 获取对应的statement的id
		MappedStatement statement = addMappedStatement(id, sqlSource, statementType, SqlCommandType.SELECT, fetchSize,
				timeout, parameterMap, parameterType, resultMapId, resultType, resultSetType, flushCache, useCache,
				resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, lang, resultSets);
		return statement;
	}
}